<script setup lang="ts">
import mermaid from "mermaid";
import { computed, onMounted, ref, watch } from "vue";
import { Component } from '@/models/component';




interface TModel extends Component {
    graphInfos: {
        graph: string
        name: string
    }[]
    relationships: {
        parent: string
        node: string
        child: string
    }[]
}


const props = defineProps<{ model: TModel }>()
const model = props.model



mermaid.initialize({ startOnLoad: false, securityLevel: 'loose' })

const divRef = ref(null as unknown as HTMLDivElement)
const cpId = `mermaid_${model.id}`
const clickCallbackName = `clickFn_${cpId}`



function useClick(model: TModel) {
    const graphInfosMap = new Map<string, string>(
        model.graphInfos.map(d => [d.name, d.graph])
    )
    const relationshipMap = new Map<string, string>()

    const graphNameStack = ref([model.graphInfos[0].name])
    const curGraphName = computed(() => graphNameStack.value[graphNameStack.value.length - 1])
    const curGraph = computed(() => graphInfosMap.get(curGraphName.value)!)
    const hasPreGraph = computed(() => graphNameStack.value.length > 1)


    const getRelKey = (graphName: string, node: string) => `${graphName}|${node}`

    // reset new graph contain click info stem to graphInfosMap
    model.relationships.forEach(rel => {

        relationshipMap.set(getRelKey(rel.parent, rel.node), rel.child)

        const graphName = rel.parent
        if (!graphInfosMap.has(graphName)) {
            throw new Error(`graph name[${graphName}] not found`);
        }


        const clickStem = `click ${rel.node} ${clickCallbackName}`
        const newGraph = `${graphInfosMap.get(graphName)}\n${clickStem}`

        graphInfosMap.set(graphName, newGraph)

    })

    function onClick(node: string) {
        const key = getRelKey(curGraphName.value, node)
        graphNameStack.value.push(relationshipMap.get(key)!)
    }

    function backTo() {
        graphNameStack.value.pop()
    }

    return {
        onClick,
        backTo,
        currentGraph: curGraph,
        hasPreGraph
    }

}

const { currentGraph, onClick, hasPreGraph, backTo } = useClick(model)


window[clickCallbackName] = function (name) {
    onClick(name)
}

onMounted(() => {


    watch(currentGraph, async curGraph => {
        const { svg, bindFunctions } = await mermaid.render(cpId, curGraph)
        divRef.value.innerHTML = svg

        bindFunctions?.(divRef.value)
    }, { immediate: true })

})


function onBackto() {
    backTo()
}

</script>

<template>
    <div :id="cpId" class="mermaid-box">
        <div class="back-to" @click="onBackto" :data-has-pre="hasPreGraph">返回</div>
        <div ref="divRef" style="height: 100%;width: 100%;">



        </div>



    </div>
</template>

<style scoped lang="less">
.mermaid-box {
    width: 100%;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0;

    &:hover .back-to[data-has-pre=true] {
        z-index: 999;
        opacity: 1;
    }


}

.back-to {
    --label-main-color: rgba(88, 140, 195, 0.9);

    z-index: -999;
    border: 1px solid var(--label-main-color);
    border-radius: 15px;
    width: 4em;
    height: 3em;

    padding: 1em 0.5em;
    display: flex;
    gap: 0.3em;
    justify-content: center;
    align-items: center;
    opacity: 0;

    user-select: none;
    cursor: pointer;

    height: 1.5em;
    transition: 0.3s;

    &:hover {
        text-decoration: underline;
    }
}
</style>